#pragma once

#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string>
#include <stack>
#include <exception>
#include <boost/shared_ptr.hpp>
#include <boost/shared_array.hpp>

using namespace std;

#define CR	'\r'
#define LF	'\n'

#ifndef min
#define max(a,b)    (((a) > (b)) ? (a) : (b))
#define min(a,b)    (((a) < (b)) ? (a) : (b))
#endif

#ifndef Min
#define Max(a,b)    (((a) > (b)) ? (a) : (b))
#define Min(a,b)    (((a) < (b)) ? (a) : (b))
#endif



inline bool InRange00(int start, int end, int value) {
	return value > start && value < end;
}
inline bool InRange01(int start, int end, int value) {
	return value > start && value <= end;
}
inline bool InRange10(int start, int end, int value) {
	return value >= start && value < end;
}
inline bool InRange11(int start, int end, int value) {
	return value >= start && value <= end;
}

inline bool InRangeX00(int start, int end, int value) {
	return value > min(start, end) && value < max(start, end);
}
inline bool InRangeX01(int start, int end, int value) {
	return value > min(start, end) && value <= max(start, end);
}
inline bool InRangeX10(int start, int end, int value) {
	return value >= min(start, end) && value < max(start, end);
}
inline bool InRangeX11(int start, int end, int value) {
	return value >= min(start, end) && value <= max(start, end);
}

inline bool isCR(char ch) {
	return ch == CR;
}
inline bool isLF(char ch) {
	return ch == LF;
}
inline bool isCROrLF(char ch) {
	return ch == CR || ch == LF;
}

//count is array length, not bytes
template<typename T>
void inline MemMove(T* dest, const T* src, size_t count) {
	if (count && dest && src && dest != src) {
		memmove(dest, src, sizeof(T) * count);
	}
}
////sizeof(void) ?, so , if given void*
//template<>
//void MemMove(void* dest, const void* src, size_t bytes) {
//	if (bytes && dest && src && dest != src) {
//		memmove(dest, src, bytes);
//	}
//}
template<typename T>
void ArrayMove(T* dest, const T* src, size_t count) {
	if (count && dest && src && dest != src) {
		if (dest < src) {
			while (count--) {
				*dest++ = *src++;
			}
		} else { //dest > src
			dest += count;
			src += count;
			while (count--) {
				*--dest = *--src;
			}
		}
	}
}
template<typename T>
void ArrayMove(T* dest, size_t destFrom, const T* src, size_t srcFrom, size_t count) {
	if (count && dest && src && (dest + destFrom) != (src + srcFrom)) {
		dest += destFrom;
		src += srcFrom;
		if (dest < src) {
			while (count--) {
				*dest++ = *src++;
			}
		} else { //dest > src
			dest += count;
			src += count;
			while (count--) {
				*--dest = *--src;
			}
		}
	}
}
template<typename T>
void inline RangeSet(T* array, size_t count, const T& value) {
	for (size_t i = 0; i < count; ++i) {
		array[i] = value;
	}
}
template<typename T>
void inline RangeSet(T* array, size_t from, size_t count, const T& value) {
	if (array && count) {
		for (size_t i = 0; i < count; ++i) {
			array[i + from] = value;
		}
	}
}
class Range {
public:
	int from;
	int to;
public:
	Range();
	Range(int from_, int to_);
};

class InvalidIndexException : public exception{

};

class NegtiveIndexException: public InvalidIndexException{

};
class IndexOutOfBoundException: public InvalidIndexException{

};
class NotFoundException: public std::exception{

};

template<typename T>
class AutoArray {
private:
	T* buffer;
	size_t capcity;
private:
	AutoArray(const AutoArray<T>& other);
	AutoArray<T> operator=(const AutoArray<T>& other);
public:
	AutoArray() :
			buffer(0), capcity(0) {

	}
	virtual ~AutoArray() {
		release();
	}
public:
	T* getBuffer() {
		return buffer;
	}
	size_t length() {
		return capcity;
	}
	void grab(AutoArray<T>& other) {
		buffer = other.buffer;
		capcity = other.capcity;
		other.buffer = 0;
		other.capcity = 0;
	}
	void allocate(size_t size) {
		assert(size > 0);
		buffer = new T[size];
		capcity = size;
	}
	void release() {
		if (buffer) {
			delete[] buffer;
		}
		buffer = 0;
		capcity = 0;
	}
};

class Logger;
class String;

Logger& operator <<(Logger& slog, const String& s);

template<typename T>
class Stack: public stack<T> {
public:
	void clear() {
//		c.clear();
		while (!empty()) {
			pop();
		}
	}
};

